home *** CD-ROM | disk | FTP | other *** search
/ Tech Arsenal 1 / Tech Arsenal (Arsenal Computer).ISO / tek-04 / mawk10.zip / BI_FUNCT.C < prev    next >
C/C++ Source or Header  |  1991-10-05  |  22KB  |  895 lines

  1.  
  2. /********************************************
  3. bi_funct.c
  4. copyright 1991, Michael D. Brennan
  5.  
  6. This is a source file for mawk, an implementation of
  7. the AWK programming language.
  8.  
  9. Mawk is distributed without warranty under the terms of
  10. the GNU General Public License, version 2, 1991.
  11. ********************************************/
  12.  
  13. /* $Log:    bi_funct.c,v $
  14.  * Revision 3.7.1.1  91/09/14  17:22:38  brennan
  15.  * VERSION 1.0
  16.  * 
  17.  * Revision 3.7  91/08/19  10:46:13  brennan
  18.  * fixed small bozo in bi_substr
  19.  * 
  20.  * Revision 3.6  91/08/13  06:50:47  brennan
  21.  * VERSION .9994
  22.  * 
  23.  * Revision 3.5  91/08/03  05:03:50  brennan
  24.  * set RLENGTH to -1 on no match
  25.  * 
  26.  * Revision 3.4  91/07/22  12:31:15  brennan
  27.  * changed how srand() handles strings
  28.  * 
  29.  * Revision 3.3  91/06/28  04:16:03  brennan
  30.  * VERSION 0.999
  31.  * 
  32.  * Revision 3.2  91/06/28  04:14:11  brennan
  33.  * srand() now returns previous seed (posix).
  34.  * 
  35.  * Revision 3.1  91/06/08  06:14:38  brennan
  36.  * VERSION 0.995
  37.  * 
  38.  * Revision 2.9  91/06/08  06:00:22  brennan
  39.  * changed how eof is marked on main_fin
  40.  * 
  41.  * Revision 2.8  91/06/03  07:47:56  brennan
  42.  * added a TEST2 to bi_substr (will I ever get it right?)
  43.  * 
  44.  * Revision 2.7  91/05/16  12:19:23  brennan
  45.  * cleanup of machine dependencies
  46.  * 
  47.  * Revision 2.6  91/05/06  15:00:37  brennan
  48.  * flush output before fork
  49.  * 
  50.  * Revision 2.5  91/04/29  07:45:00  brennan
  51.  * plugged big memory leak and fixed small bozo in bi_substr
  52.  * plugged small memory leak in gsub()
  53.  * 
  54.  * Revision 2.4  91/04/26  06:59:41  brennan
  55.  * use builtin random number generator for portability
  56.  * 
  57.  * Revision 2.3  91/04/17  06:34:00  brennan
  58.  * index("","") should be 1 not 0 for consistency with match("",//)
  59.  * 
  60.  * Revision 2.2  91/04/09  12:38:42  brennan
  61.  * added static to funct decls to satisfy STARDENT compiler
  62.  * 
  63.  * Revision 2.1  91/04/08  08:22:17  brennan
  64.  * VERSION 0.97
  65.  * 
  66. */
  67.  
  68.  
  69. #include "mawk.h"
  70. #include "bi_funct.h"
  71. #include "bi_vars.h"
  72. #include "memory.h"
  73. #include "init.h"
  74. #include "files.h"
  75. #include "fin.h"
  76. #include "field.h"
  77. #include "regexp.h"
  78. #include "repl.h"
  79. #include <math.h>
  80.  
  81.  
  82. /* statics */
  83. static STRING *PROTO(gsub, (PTR, CELL *, char *, int) ) ;
  84. static void  PROTO( fplib_err, (char *, double, char *) ) ;
  85.  
  86.  
  87. /* global for the disassembler */
  88. BI_REC  bi_funct[] = { /* info to load builtins */
  89.  
  90. "index" , bi_index , 2, 2 ,
  91. "substr" , bi_substr, 2, 3,
  92. "sprintf" , bi_sprintf, 1, 255,
  93. "sin", bi_sin , 1, 1 ,
  94. "cos", bi_cos , 1, 1 ,
  95. "atan2", bi_atan2, 2,2,
  96. "exp", bi_exp, 1, 1,
  97. "log", bi_log , 1, 1 ,
  98. "int", bi_int, 1, 1,
  99. "sqrt", bi_sqrt, 1, 1,
  100. "rand" , bi_rand, 0, 0,
  101. "srand", bi_srand, 0, 1,
  102. "close", bi_close, 1, 1,
  103. "system", bi_system, 1, 1,
  104.  
  105. #if  MSDOS   /* this might go away, when pipes and system are added
  106.               for MSDOS  */
  107. "errmsg", bi_errmsg, 1, 1,
  108. #endif
  109.  
  110. #ifdef THINK_C    /* I doubt this will ever go away for the Macintosh
  111.            Toy Operating System */
  112. "errmsg", bi_errmsg, 1, 1,
  113. #endif
  114.  
  115. (char *) 0, (PF_CP) 0, 0, 0 } ;
  116.  
  117.  
  118.  
  119. void bi_funct_init()
  120. { register BI_REC *p = bi_funct ;
  121.   register SYMTAB *stp ;
  122.  
  123.   while ( p->name )
  124.   { stp = insert( p->name ) ;
  125.     stp->type = ST_BUILTIN ;
  126.     stp->stval.bip = p++ ;
  127.   }
  128.   /* seed rand() off the clock */
  129.   { CELL c ;
  130.  
  131.     c.type = 0 ; (void) bi_srand(&c) ;
  132.   }
  133.  
  134.   stp = insert( "length") ;
  135.   stp->type = ST_LENGTH ;
  136. }
  137.  
  138. /**************************************************
  139.  string builtins (except split (in split.c) and [g]sub (at end))
  140.  **************************************************/
  141.  
  142. CELL *bi_length(sp)
  143.   register  CELL *sp ;
  144. { unsigned len ;
  145.  
  146.   if ( sp->type < C_STRING ) cast1_to_s(sp) ;
  147.   len = string(sp)->len ;
  148.  
  149.   free_STRING( string(sp) ) ;
  150.   sp->type = C_DOUBLE ;
  151.   sp->dval = (double) len ;
  152.  
  153.   return sp ;
  154. }
  155.  
  156. char *str_str(target, key , key_len)
  157.   register char *target, *key ;
  158.   unsigned key_len ;
  159.   switch( key_len )
  160.   { case 0 :  return (char *) 0 ;
  161.     case 1 :  return strchr( target, *key) ;
  162.     case 2 :
  163.         while ( target = strchr(target, *key) )
  164.           if ( target[1] == key[1] )  return  target ;
  165.           else target++ ;
  166.         /*failed*/
  167.         return (char *) 0 ;
  168.   }
  169.   key_len-- ;
  170.   while ( target = strchr(target, *key) )
  171.         if ( memcmp(target+1, key+1, SIZE_T(key_len)) == 0 ) return target ;
  172.         else target++ ;
  173.   /*failed*/
  174.   return (char *) 0 ;
  175. }
  176.  
  177.  
  178.  
  179. CELL *bi_index(sp)
  180.   register CELL *sp ;
  181. { register int idx ;
  182.   unsigned len ;
  183.   char *p ;
  184.  
  185.   sp-- ;
  186.   if ( TEST2(sp) != TWO_STRINGS )
  187.         cast2_to_s(sp) ;
  188.  
  189.   if ( len = string(sp+1)->len )
  190.     idx = (p = str_str(string(sp)->str,string(sp+1)->str,len))
  191.           ? p - string(sp)->str + 1 : 0 ;
  192.  
  193.   else  /* index of the empty string */
  194.     idx = 1 ;
  195.   
  196.   free_STRING( string(sp) ) ;
  197.   free_STRING( string(sp+1) ) ;
  198.   sp->type = C_DOUBLE ;
  199.   sp->dval = (double) idx ;
  200.   return sp ;
  201. }
  202.  
  203. /*  substr(s, i, n)
  204.     if l = length(s)
  205.     then get the characters
  206.     from  max(1,i) to min(l,n-i-1) inclusive */
  207.  
  208. CELL *bi_substr(sp)
  209.   CELL *sp ;
  210. { int n_args, len ;
  211.   register int i, n ;
  212.   STRING *sval ;  /* substr(sval->str, i, n) */
  213.  
  214.   n_args = sp->type ;
  215.   sp -= n_args ;
  216.   if ( sp->type != C_STRING )  cast1_to_s(sp) ;
  217.       /* don't use < C_STRING shortcut */
  218.   sval = string(sp) ;
  219.  
  220.   if ( (len = sval->len) == 0 )  /* substr on null string */
  221.   {  if ( n_args == 3 )  cell_destroy(sp+2) ;
  222.      cell_destroy(sp+1) ;
  223.      return sp ;
  224.   }
  225.  
  226.   if ( n_args == 2 )  
  227.   { n = 0x7fff  ;  /* essentially infinity */
  228.     if ( sp[1].type != C_DOUBLE ) cast1_to_d(sp+1) ; 
  229.   }
  230.   else
  231.   { if ( TEST2(sp+1) != TWO_DOUBLES ) cast2_to_d(sp+1) ;
  232.     n = (int) sp[2].dval ;
  233.   }
  234.   i = (int) sp[1].dval - 1 ; /* i now indexes into string */
  235.  
  236.   if ( i < 0 ) { n += i ; i = 0 ; }
  237.   if ( n > len - i )  n = len - i ;
  238.  
  239.   if ( n <= 0 )  /* the null string */
  240.   { 
  241.     sp->ptr = (PTR) &null_str ;
  242.     null_str.ref_cnt++ ;
  243.   }
  244.   else  /* got something */
  245.   { 
  246.     sp->ptr = (PTR) new_STRING((char *)0, n) ;
  247.     (void) memcpy(string(sp)->str, sval->str + i, SIZE_T(n)) ;
  248.   }
  249.  
  250.   free_STRING(sval) ;
  251.   return sp ;
  252.  
  253. /*
  254.   match(s,r)
  255.   sp[0] holds r, sp[-1] holds s
  256. */
  257.  
  258. CELL *bi_match(sp)
  259.   register CELL *sp ;
  260.   char *p ;
  261.   unsigned length ;
  262.  
  263.   if ( sp->type != C_RE )  cast_to_RE(sp) ;
  264.   if ( (--sp)->type < C_STRING )  cast1_to_s(sp) ;
  265.  
  266.   cell_destroy( & bi_vars[RSTART] ) ;
  267.   cell_destroy( & bi_vars[RLENGTH] ) ;
  268.   bi_vars[RSTART].type = C_DOUBLE ;
  269.   bi_vars[RLENGTH].type = C_DOUBLE ;
  270.  
  271.   p = REmatch(string(sp)->str, (sp+1)->ptr, &length) ;
  272.  
  273.   if ( p )
  274.   { sp->dval = (double) ( p - string(sp)->str + 1 ) ;
  275.     bi_vars[RLENGTH].dval = (double) length ;
  276.   }
  277.   else
  278.   { sp->dval = 0.0 ;
  279.     bi_vars[RLENGTH].dval = -1.0 ; /* posix */
  280.   }
  281.  
  282.   free_STRING(string(sp)) ;
  283.   sp->type = C_DOUBLE ;
  284.  
  285.   bi_vars[RSTART].dval = sp->dval ;
  286.  
  287.   return sp ;
  288. }
  289.  
  290.  
  291. /************************************************
  292.   arithemetic builtins
  293.  ************************************************/
  294.  
  295. static void fplib_err( fname, val, error)
  296.   char *fname ;
  297.   double val ;
  298.   char *error ;
  299. {
  300.   rt_error("%s(%g) : %s" , fname, val, error) ;
  301. }
  302.  
  303.  
  304. CELL *bi_sin(sp)
  305.   register CELL *sp ;
  306. #if ! STDC_MATHERR
  307.   if ( sp->type != C_DOUBLE )  cast1_to_d(sp) ;
  308.   sp->dval = sin( sp->dval ) ;
  309.   return sp ;
  310. #else
  311.   double x ;
  312.  
  313.   errno = 0 ;
  314.   if ( sp->type != C_DOUBLE )  cast1_to_d(sp) ;
  315.   x = sp->dval ;
  316.   sp->dval = sin( sp->dval ) ;
  317.   if ( errno )  fplib_err("sin", x, "loss of precision") ;
  318.   return sp ;
  319. #endif
  320. }
  321.  
  322. CELL *bi_cos(sp)
  323.   register CELL *sp ;
  324. #if ! STDC_MATHERR
  325.   if ( sp->type != C_DOUBLE )  cast1_to_d(sp) ;
  326.   sp->dval = cos( sp->dval ) ;
  327.   return sp ;
  328. #else
  329.   double x ;
  330.  
  331.   errno = 0 ;
  332.   if ( sp->type != C_DOUBLE )  cast1_to_d(sp) ;
  333.   x = sp->dval ;
  334.   sp->dval = cos( sp->dval ) ;
  335.   if ( errno )  fplib_err("cos", x, "loss of precision") ;
  336.   return sp ;
  337. #endif
  338. }
  339.  
  340. CELL *bi_atan2(sp)
  341.   register CELL *sp ;
  342. #if  !  STDC_MATHERR
  343.   sp-- ;
  344.   if ( TEST2(sp) != TWO_DOUBLES ) cast2_to_d(sp) ;
  345.   sp->dval = atan2(sp->dval, (sp+1)->dval) ;
  346.   return sp ;
  347. #else
  348.  
  349.   errno = 0 ;
  350.   sp-- ;
  351.   if ( TEST2(sp) != TWO_DOUBLES ) cast2_to_d(sp) ;
  352.   sp->dval = atan2(sp->dval, (sp+1)->dval) ;
  353.   if ( errno ) rt_error("atan2(0,0) : domain error") ;
  354.   return sp ;
  355. #endif
  356. }
  357.  
  358. CELL *bi_log(sp)
  359.   register CELL *sp ;
  360. #if ! STDC_MATHERR
  361.   if ( sp->type != C_DOUBLE )  cast1_to_d(sp) ;
  362.   sp->dval = log( sp->dval ) ;
  363.   return sp ;
  364. #else
  365.   double  x ;
  366.  
  367.   errno = 0 ;
  368.   if ( sp->type != C_DOUBLE )  cast1_to_d(sp) ;
  369.   x = sp->dval ;
  370.   sp->dval = log( sp->dval ) ;
  371.   if ( errno )  fplib_err("log", x, "domain error") ;
  372.   return sp ;
  373. #endif
  374. }
  375.  
  376. CELL *bi_exp(sp)
  377.   register CELL *sp ;
  378. #if  ! STDC_MATHERR
  379.   if ( sp->type != C_DOUBLE )  cast1_to_d(sp) ;
  380.   sp->dval = exp(sp->dval) ;
  381.   return sp ;
  382. #else
  383.   double  x ;
  384.  
  385.   errno = 0 ;
  386.   if ( sp->type != C_DOUBLE )  cast1_to_d(sp) ;
  387.   x = sp->dval ;
  388.   sp->dval = exp(sp->dval) ;
  389.   if ( errno && sp->dval)  fplib_err("exp", x, "overflow") ;
  390.      /* on underflow sp->dval==0, ignore */
  391.   return sp ;
  392. #endif
  393. }
  394.  
  395. CELL *bi_int(sp)
  396.   register CELL *sp ;
  397. { if ( sp->type != C_DOUBLE )  cast1_to_d(sp) ;
  398.   sp->dval = sp->dval >= 0.0 ? floor( sp->dval ) : ceil(sp->dval)  ;
  399.   return sp ;
  400. }
  401.  
  402. CELL *bi_sqrt(sp)
  403.   register CELL *sp ;
  404. #if  ! STDC_MATHERR
  405.   if ( sp->type != C_DOUBLE )  cast1_to_d(sp) ;
  406.   sp->dval = sqrt( sp->dval ) ;
  407.   return sp ;
  408. #else
  409.   double x ;
  410.  
  411.   errno = 0 ;
  412.   if ( sp->type != C_DOUBLE )  cast1_to_d(sp) ;
  413.   x = sp->dval ;
  414.   sp->dval = sqrt( sp->dval ) ;
  415.   if ( errno )  fplib_err("sqrt", x, "domain error") ;
  416.   return sp ;
  417. #endif
  418. }
  419.  
  420. #ifdef  __TURBOC__
  421. long  biostime(int, long) ;
  422. #define  time(x)  biostime(0,0L)
  423. #else
  424. #ifdef THINK_C
  425. #include <time.h>
  426. #else
  427. #include <sys/types.h>
  428. #endif
  429. #endif
  430.  
  431.  
  432. /* For portability, we'll use our own random number generator , taken
  433.    from:  Park, SK and Miller KW, "Random Number Generators:
  434.    Good Ones are Hard to Find", CACM, 31, 1192-1201, 1988.
  435. */
  436.  
  437. static long seed ;  /* must be >=1 and <= 2^31-1 */
  438. static CELL cseed ; /* argument of last call to srand() */
  439.  
  440. #define         M       0x7fffffff   /* 2^31-1 */
  441.  
  442. CELL *bi_srand(sp)
  443.   register CELL *sp ;
  444. { CELL c ;
  445.  
  446.   if ( sp->type == 0 ) /* seed off clock */
  447.   { (void) cellcpy(sp, &cseed) ;
  448.     cell_destroy(&cseed) ;
  449.     cseed.type = C_DOUBLE ;
  450.     cseed.dval = (double) time((time_t*) 0) ;
  451.   }
  452.   else /* user seed */
  453.   { sp-- ;
  454.     /* swap cseed and *sp ; don't need to adjust ref_cnts */
  455.     c = *sp ; *sp = cseed ; cseed = c ;
  456.   }
  457.  
  458.   /* The old seed is now in *sp ; move the value in cseed to
  459.      seed in range 1 to M */
  460.  
  461.   (void) cellcpy(&c, &cseed) ;
  462.   if ( c.type == C_NOINIT )  cast1_to_d(&c) ;
  463.  
  464.   seed =  c.type == C_DOUBLE ? ((int)c.dval & M) % M + 1 :
  465.                         hash(string(&c)->str) % M + 1 ;
  466.  
  467.   cell_destroy(&c) ;
  468.  
  469.   /* crank it once so close seeds don't give a close 
  470.        first result  */
  471. #define   A     16807
  472. #define   Q     127773   /* M/A */
  473. #define   R     2836     /* M%A */
  474.   seed = A * (seed%Q) - R * (seed/Q) ;
  475.   if ( seed <= 0 )  seed += M ;
  476.  
  477.   return sp ;
  478. }
  479.     
  480. CELL *bi_rand(sp)
  481.   register CELL *sp ;
  482.   register long test ;
  483.  
  484.   test = A * (seed%Q) - R * (seed/Q) ;
  485.   if ( test <= 0 )  test += M ;
  486.  
  487.   (++sp)->type = C_DOUBLE ;
  488.   sp->dval = (double)( seed = test ) / (double) M ;
  489.   return sp ;
  490.  
  491. #undef   A
  492. #undef   M
  493. #undef   Q
  494. #undef   R
  495. }
  496.  
  497. /*************************************************
  498.  miscellaneous builtins
  499.  close, system and getline
  500.  *************************************************/
  501.  
  502. CELL *bi_close(sp)
  503.   register CELL *sp ;
  504. { int x ;
  505.  
  506.   if ( sp->type < C_STRING ) cast1_to_s(sp) ;
  507.   x = file_close( (STRING *) sp->ptr) ;
  508.   free_STRING( string(sp) ) ;
  509.   sp->type = C_DOUBLE ;
  510.   sp->dval = (double) x ;
  511.   return sp ;
  512. }
  513.  
  514. #if   ! MSDOS
  515. #ifndef THINK_C
  516. CELL *bi_system(sp)
  517.   CELL *sp ;
  518. { int pid ;
  519.   unsigned ret_val ;
  520.  
  521.   if ( sp->type < C_STRING ) cast1_to_s(sp) ;
  522.  
  523.   fflush(stdout) ; fflush(stderr) ;
  524.  
  525.   switch( pid = fork() )
  526.   { case -1 :  /* fork failed */
  527.  
  528.        errmsg(errno, "could not create a new process") ;
  529.        ret_val = 128 ;
  530.        break ;
  531.  
  532.     case  0  :  /* the child */
  533.        (void) execl(shell, shell, "-c", string(sp)->str, (char *) 0) ;
  534.        /* if get here, execl() failed */
  535.        errmsg(errno, "execute of %s failed", shell) ;
  536.        fflush(stderr) ;
  537.        _exit(128) ;
  538.  
  539.     default   :  /* wait for the child */
  540.        ret_val = wait_for(pid) ;
  541.        if ( ret_val & 0xff ) ret_val = 128 ;
  542.        else  ret_val = (ret_val & 0xff00) >> 8 ;
  543.        break ;
  544.   }
  545.  
  546.   cell_destroy(sp) ;
  547.   sp->type = C_DOUBLE ;
  548.   sp->dval = (double) ret_val ;
  549.   return sp ;
  550. }
  551.  
  552. #else   /* THINK_C */
  553.  
  554. CELL *bi_system( sp )
  555.   register CELL *sp ;
  556. { rt_error("no system call for the Macintosh Toy Operating System!!!") ;
  557.   return sp ;
  558. }
  559.  
  560. /* prints errmsgs for the Macintosh  */
  561. CELL *bi_errmsg(sp)
  562.   register CELL *sp ;
  563. {
  564.   cast1_to_s(sp) ;
  565.   fprintf(stderr, "%s\n", string(sp)->str) ;
  566.   free_STRING(string(sp)) ;
  567.   sp->type = C_DOUBLE ;
  568.   sp->dval = 0.0 ;
  569.   return sp ;
  570. }
  571.  
  572. #endif
  573. #else   /*  MSDOS   */
  574.  
  575. CELL *bi_system( sp )
  576.   register CELL *sp ;
  577. { rt_error("no system call in MsDos --yet") ;
  578.   return sp ;
  579. }
  580.  
  581. /* prints errmsgs for MSDOS  */
  582. CELL *bi_errmsg(sp)
  583.   register CELL *sp ;
  584. {
  585.   cast1_to_s(sp) ;
  586.   fprintf(stderr, "%s\n", string(sp)->str) ;
  587.   free_STRING(string(sp)) ;
  588.   sp->type = C_DOUBLE ;
  589.   sp->dval = 0.0 ;
  590.   return sp ;
  591. }
  592. #endif
  593.  
  594.  
  595. /*  getline()  */
  596.  
  597. /*  if type == 0 :  stack is 0 , target address
  598.  
  599.     if type == F_IN : stack is F_IN, expr(filename), target address
  600.  
  601.     if type == PIPE_IN : stack is PIPE_IN, target address, expr(pipename)
  602. */
  603.  
  604. CELL *bi_getline(sp)
  605.   register CELL *sp ;
  606.   CELL tc , *cp ;
  607.   char *p ;
  608.   unsigned len ;
  609.   FIN *fin_p ;
  610.  
  611.  
  612.   switch( sp->type )
  613.   { 
  614.     case 0 :
  615.         sp-- ;
  616.         if ( ! main_fin )  open_main() ;
  617.     
  618.         if ( ! (p = FINgets(main_fin, &len)) )
  619.                 goto  eof ;
  620.  
  621.         cp = (CELL *) sp->ptr ;
  622.         if ( TEST2(bi_vars+NR) != TWO_DOUBLES ) cast2_to_d(bi_vars+NR) ;
  623.         bi_vars[NR].dval += 1.0 ;
  624.         bi_vars[FNR].dval += 1.0 ;
  625.         break ;
  626.  
  627.     case  F_IN :
  628.         sp-- ;
  629.         if ( sp->type < C_STRING ) cast1_to_s(sp) ;
  630.         fin_p = (FIN *) file_find(sp->ptr, F_IN) ;
  631.         free_STRING(string(sp) ) ;
  632.         sp-- ;
  633.  
  634.         if ( ! fin_p )   goto open_failure ;
  635.         if ( ! (p = FINgets(fin_p, &len)) )  goto eof ; 
  636.         cp = (CELL *) sp->ptr ;
  637.         break ;
  638.  
  639.     case PIPE_IN :
  640.         sp -= 2 ;
  641.         if ( sp->type < C_STRING ) cast1_to_s(sp) ;
  642.         fin_p = (FIN *) file_find(sp->ptr, PIPE_IN) ;
  643.         free_STRING(string(sp)) ;
  644.  
  645.         if ( ! fin_p )   goto open_failure ;
  646.         if ( ! (p = FINgets(fin_p, &len)) )  goto eof ; 
  647.         cp = (CELL *) (sp+1)->ptr ;
  648.         break ;
  649.  
  650.     default : bozo("type in bi_getline") ;
  651.  
  652.   }
  653.  
  654.   /* we've read a line , store it */
  655.  
  656.     if ( len == 0 )
  657.     { tc.type = C_STRING ; 
  658.       tc.ptr = (PTR) &null_str ; 
  659.       null_str.ref_cnt++ ;
  660.     }
  661.     else
  662.     { tc.type = C_MBSTRN ;
  663.       tc.ptr = (PTR) new_STRING((char *) 0, len) ;
  664.       (void) memcpy( string(&tc)->str, p, SIZE_T(len)) ;
  665.     }
  666.  
  667.     if ( cp  >= field && cp < field+NUM_FIELDS )
  668.            field_assign(cp-field, &tc) ;
  669.     else
  670.     { cell_destroy(cp) ;
  671.       (void) cellcpy(cp, &tc) ;
  672.     }
  673.  
  674.     cell_destroy(&tc) ;
  675.  
  676.   sp->dval = 1.0  ;  goto done ;
  677.  
  678. open_failure :
  679.   sp->dval = -1.0  ; goto done ;
  680.  
  681. eof :
  682.   sp->dval = 0.0  ;  /* fall thru to done  */
  683.  
  684. done :
  685.   sp->type = C_DOUBLE  ;
  686.   return sp ;
  687. }
  688.  
  689. /**********************************************
  690.  sub() and gsub()
  691.  **********************************************/
  692.  
  693. /* entry:  sp[0] = address of CELL to sub on
  694.            sp[-1] = substitution CELL
  695.            sp[-2] = regular expression to match
  696. */
  697.  
  698. CELL *bi_sub( sp )
  699.   register CELL *sp ;
  700. { CELL *cp ; /* pointer to the replacement target */
  701.   CELL tc ;  /* build the new string here */
  702.   CELL sc ;  /* copy of the target CELL */
  703.   char *front, *middle, *back ; /* pieces */
  704.   unsigned front_len, middle_len, back_len ;
  705.  
  706.   sp -= 2 ;
  707.   if ( sp->type != C_RE )  cast_to_RE(sp) ;
  708.   if ( sp[1].type != C_REPL && sp[1].type != C_REPLV )
  709.               cast_to_REPL(sp+1) ;
  710.   cp = (CELL *) (sp+2)->ptr ;
  711.   /* make a copy of the target, because we won't change anything
  712.      including type unless the match works */
  713.   (void) cellcpy(&sc, cp) ;
  714.   if ( sc.type < C_STRING ) cast1_to_s(&sc) ;
  715.   front = string(&sc)->str ;
  716.  
  717.   if ( middle = REmatch(front, sp->ptr, &middle_len) )
  718.   { 
  719.     front_len = middle - front ;
  720.     back = middle + middle_len ; 
  721.     back_len = string(&sc)->len - front_len - middle_len ;
  722.  
  723.     if ( (sp+1)->type == C_REPLV ) 
  724.     { STRING *sval = new_STRING((char *) 0, middle_len) ;
  725.  
  726.       (void) memcpy(sval->str, middle, SIZE_T(middle_len)) ;
  727.       (void) replv_to_repl(sp+1, sval) ;
  728.       free_STRING(sval) ;
  729.     }
  730.  
  731.     tc.type = C_STRING ;
  732.     tc.ptr = (PTR) new_STRING((char *) 0, 
  733.              front_len + string(sp+1)->len + back_len ) ;
  734.  
  735.     { char *p = string(&tc)->str ;
  736.  
  737.       if ( front_len )
  738.       { (void) memcpy(p, front, SIZE_T(front_len)) ;
  739.         p += front_len ;
  740.       }
  741.       if ( string(sp+1)->len )
  742.       { (void) memcpy(p, string(sp+1)->str, SIZE_T(string(sp+1)->len)) ;
  743.         p += string(sp+1)->len ;
  744.       }
  745.       if ( back_len )  (void) memcpy(p, back, SIZE_T(back_len)) ;
  746.     }
  747.  
  748.     if ( cp  >= field && cp < field+NUM_FIELDS )
  749.            field_assign(cp-field, &tc) ;
  750.     else
  751.     { cell_destroy(cp) ;
  752.       (void) cellcpy(cp, &tc) ;
  753.     }
  754.  
  755.     free_STRING(string(&tc)) ;
  756.   }
  757.  
  758.   free_STRING(string(&sc)) ;
  759.   repl_destroy(sp+1) ;
  760.   sp->type = C_DOUBLE ;
  761.   sp->dval = middle != (char *) 0 ? 1.0 : 0.0 ;
  762.   return sp ;
  763. }
  764.  
  765. static  unsigned repl_cnt ;  /* number of global replacements */
  766.  
  767. /* recursive global subsitution 
  768.    dealing with empty matches makes this mildly painful
  769. */
  770.  
  771. static STRING *gsub( re, repl, target, flag)
  772.   PTR  re ;
  773.   CELL *repl ;  /* always of type REPL or REPLV, 
  774.        destroyed by caller */
  775.   char *target ;
  776.   int flag ; /* if on, match of empty string at front is OK */
  777. { char *front, *middle ;
  778.   STRING *back ;
  779.   unsigned front_len, middle_len ;
  780.   STRING  *ret_val ;
  781.   CELL xrepl ; /* a copy of repl so we can change repl */
  782.  
  783.   if ( ! (middle = REmatch(target, re, &middle_len)) )
  784.       return  new_STRING(target) ; /* no match */
  785.  
  786.   (void) cellcpy(&xrepl, repl) ;
  787.  
  788.   if ( !flag && middle_len == 0 && middle == target ) 
  789.   { /* match at front that's not allowed */
  790.  
  791.     if ( *target == 0 )  /* target is empty string */
  792.     { repl_destroy(&xrepl) ;
  793.       null_str.ref_cnt++ ;
  794.       return & null_str ;
  795.     }
  796.     else
  797.     { char xbuff[2] ;
  798.  
  799.       front_len = 0 ;
  800.       /* make new repl with target[0] */
  801.       repl_destroy(repl) ;
  802.       xbuff[0] = *target++ ;  xbuff[1] = 0 ;
  803.       repl->type = C_REPL ;
  804.       repl->ptr = (PTR) new_STRING( xbuff ) ;
  805.       back = gsub(re, &xrepl, target, 1) ;
  806.     }
  807.   }
  808.   else  /* a match that counts */
  809.   { repl_cnt++ ;
  810.  
  811.     front = target ;
  812.     front_len = middle - target ;
  813.  
  814.     if ( *middle == 0 )  /* matched back of target */
  815.     { back = &null_str ; null_str.ref_cnt++ ; }
  816.     else back = gsub(re, &xrepl, middle + middle_len, 0) ;
  817.       
  818.     /* patch the &'s if needed */
  819.     if ( repl->type == C_REPLV )
  820.     { STRING *sval = new_STRING((char *) 0, middle_len) ;
  821.  
  822.       (void) memcpy(sval->str, middle, SIZE_T(middle_len)) ;
  823.       (void) replv_to_repl(repl, sval) ;
  824.       free_STRING(sval) ;
  825.     }
  826.   }
  827.  
  828.   /* put the three pieces together */
  829.   ret_val = new_STRING((char *)0,
  830.               front_len + string(repl)->len + back->len); 
  831.   { char *p = ret_val->str ;
  832.  
  833.     if ( front_len )
  834.     { (void) memcpy(p, front, SIZE_T(front_len)) ; p += front_len ; }
  835.     if ( string(repl)->len )
  836.     { (void) memcpy(p, string(repl)->str, SIZE_T(string(repl)->len)) ;
  837.       p += string(repl)->len ;
  838.     }
  839.     if ( back->len ) (void) memcpy(p, back->str, SIZE_T(back->len)) ;
  840.   }
  841.  
  842.   /* cleanup, repl is freed by the caller */
  843.   repl_destroy(&xrepl) ;
  844.   free_STRING(back) ;
  845.  
  846.   return ret_val ;
  847. }
  848.  
  849. /* set up for call to gsub() */
  850. CELL *bi_gsub( sp )
  851.   register CELL *sp ;
  852. { CELL *cp ;  /* pts at the replacement target */
  853.   CELL sc  ;  /* copy of replacement target */
  854.   CELL tc  ;  /* build the result here */
  855.  
  856.   sp -= 2 ;
  857.   if ( sp->type != C_RE ) cast_to_RE(sp) ;
  858.   if ( (sp+1)->type != C_REPL && (sp+1)->type != C_REPLV )
  859.           cast_to_REPL(sp+1) ;
  860.  
  861.   (void) cellcpy(&sc, cp = (CELL *)(sp+2)->ptr) ;
  862.   if ( sc.type < C_STRING ) cast1_to_s(&sc) ;
  863.  
  864.   repl_cnt = 0 ;
  865.   tc.ptr = (PTR) gsub(sp->ptr, sp+1, string(&sc)->str, 1) ;
  866.  
  867.   if ( repl_cnt )
  868.   { tc.type = C_STRING ;
  869.  
  870.     if ( cp >= field && cp < field + NUM_FIELDS )
  871.         field_assign(cp-field, &tc) ;
  872.     else
  873.     { cell_destroy(cp) ; (void) cellcpy(cp, &tc) ; }
  874.   }
  875.  
  876.   /* cleanup */
  877.   free_STRING(string(&sc)) ; free_STRING(string(&tc)) ;
  878.   repl_destroy(sp+1) ;
  879.  
  880.   sp->type = C_DOUBLE ;
  881.   sp->dval = (double) repl_cnt ;
  882.   return sp ;
  883. }
  884.